/*
 * GraphPanel.java
 *
 * Created on den 30 november 2007, 17:08
 */
package grex.Graphics;

import grex.GP;
import grex.Prediction;
import grex.genes.Gene;

import java.awt.Color;
import java.awt.Graphics;
import java.awt.event.ComponentEvent;
import java.awt.event.ComponentListener;
import java.util.ArrayList;

/**
 *
 * @author RIK
 */
public class GraphPanel extends javax.swing.JPanel implements ComponentListener, IOutputPanel {

    private ArrayList<GPoint> gPoints;
    private ArrayList<GPoint> rPoints;
    private ArrayList<Gene> leafs;
    private int nrOfTrains;
    private int GRAPH_HEIGHT=200;
    private double xMax = Double.MIN_VALUE, yMax = Double.MIN_VALUE, xMin = Double.MAX_VALUE, yMin = Double.MAX_VALUE;

    /**
     * Creates new form GraphPanel
     */
    public GraphPanel() {
        initComponents();
        this.addComponentListener(this);
    }

    public GraphPanel(ArrayList<Prediction> train, ArrayList<Prediction> test) {
        initComponents();
        this.addComponentListener(this);
        init(train, test);
    }
    
    public void init(GP gp){
        init(gp.getOrderedTrain(),gp.getOrderedTest());
    }

    public void init(ArrayList<Prediction> train, ArrayList<Prediction> test) {
        xMax = train.size() + test.size();
        yMax = Double.MIN_VALUE;
        xMin = 0;
        yMin = 0;//Double.MAX_VALUE;
        double x, gY, rY;
        gPoints = new ArrayList<GPoint>();
        rPoints = new ArrayList<GPoint>();

        nrOfTrains = train.size();
        for (Prediction p : train) {
            x = gPoints.size();
            gY = p.getPrediction();
            rY = p.getTargetValue();
            /*if (gY > yMax) {
                yMax = gY;
            }
            if (gY < yMin) {
                yMin = gY;
            }*/
            if (rY > yMax) {
                yMax = rY;
            }
            if (rY < yMin) {
                yMin = rY;
            }
            gPoints.add(new GPoint(x, gY, p.getGene(), false));
            rPoints.add(new GPoint(x, rY, p.getGene(), true));

            //gPoints.add(new GPoint(x,gY,p.getProbabillity(),p.getLowerProbabillity(),p.getGene(), false));
            //rPoints.add(new GPoint(x,rY,p.getProbabillity(),p.getLowerProbabillity(),p.getGene(), true));
        }
  //      yMax = Double.MIN_VALUE;        
   //     yMin = 0;//Double.MAX_VALUE;
   
        
        for (Prediction p : test) {
            x = gPoints.size();
            gY = p.getPrediction();
            rY = p.getTargetValue();
         /*   if (gY > yMax) {
                yMax = gY;
            }
            if (gY < yMin) {
                yMin = gY;
            }*/
            if (rY > yMax) {
                yMax = rY;
            }
            if (rY < yMin) {
                yMin = rY;
            }
            gPoints.add(new GPoint(x, gY, p.getGene(), false));
            rPoints.add(new GPoint(x, rY, p.getGene(), true));
            
            
            //            gPoints.add(new GPoint(x,gY,p.getProbabillity(),p.getLowerProbabillity(),p.getGene(), false));
//            rPoints.add(new GPoint(x,rY,p.getProbabillity(),p.getLowerProbabillity(),p.getGene(), true));
        }        
        update();
    }

    public void update() {
        this.removeAll();
        addGraphPoints();
        validate();
        repaint();
    }
    


    public void highLightGraphPoints(Gene leaf, ArrayList<Gene> leafs) {
        for (int i = 0; i < gPoints.size(); i++) {
            gPoints.get(i).highLigt(leafs.get(i).equals(leaf));

        }
          repaint();
    }

    public void addGraphPoints() {
        double x, y;
        GRAPH_HEIGHT = (int) (this.getHeight()*0.9);
        int ground = this.getHeight() - GRAPH_HEIGHT;
        if (gPoints != null) {
            int w = (int) gPoints.get(0).getSize().getHeight();
            for (GPoint p : gPoints) {
                x = Math.round((getWidth() - w) * ((p.getXValue() - xMin) / (xMax - xMin)));
                y = ground +(int) Math.round(GRAPH_HEIGHT - w - (GRAPH_HEIGHT - w) * ((p.getYValue() - yMin) / (yMax - yMin)));
                add(p, new org.netbeans.lib.awtextra.AbsoluteConstraints((int)x, (int) y, -1, -1));
            }
            for (GPoint p : rPoints) {
                x = Math.round((getWidth() - w) * ((p.getXValue() - xMin) / (xMax - xMin)));
                y = ground +(int) Math.round(GRAPH_HEIGHT - w - (GRAPH_HEIGHT - w) * ((p.getYValue() - yMin) / (yMax - yMin)));
                add(p, new org.netbeans.lib.awtextra.AbsoluteConstraints((int) x, (int) y, -1, -1));
            }
        }
    }
/*         public void drawDotedLine(double x1,double y1,double x2, double y2, double width, Graphics g){
             double x=x1;
             double y=y1;
             double k = (x1-x2)/(y1-y2);
             int a=3;
             boolean draw=true;
             for(int i=0; x < x2 && y< y2;i+=a){
                 if(draw){
                    drawLine()
                 }
                 draw =!draw;
             }
         }
  */  
     public void drawLine(double x1,double y1,double x2, double y2, double width, Graphics g){
        y1+=4;
        x1+=4;
        y2+=4;
        x2+=4;
         int[] xs = new int[4];
        int[] ys = new int[4];
        double dx = x1-x2;
        double dy = y1-y2;
        double a = Math.abs(Math.atan(dy/dx));
        double c = a;
        while(c>Math.PI/2)
            c-=Math.PI/2;
        c=Math.PI/2-c;
        int xDiff = (int) Math.ceil(Math.cos(c)*width/2);
        int yDiff = (int) Math.ceil(Math.sin(c)*width/2);
        
        xs[0] = (int)x1 - xDiff;
        xs[1] = (int)x1 + xDiff;
        xs[2] = (int)x2 + xDiff;
        xs[3] = (int)x2 - xDiff;
        
        ys[0] = (int)y1 - yDiff;
        ys[1] = (int)y1 + yDiff; 
        ys[2] = (int)y2 + yDiff;
        ys[3] = (int)y2 - yDiff;
        

        g.fillPolygon(xs, ys,xs.length);
    }

    public void paintComponent(Graphics g) {
        super.paintComponent(g);
        if(gPoints!=null){
        int[] xPoints = new int[gPoints.size() * 2];
        int[] yPoints = new int[gPoints.size() * 2];
        GPoint g1, g2;
        double g1Error = 0, g2Error = 0, g1LowError = 0, g2LowError = 0;
        int w = 0;
        if (gPoints != null) {
             w = ((int) getComponent(0).getSize().getWidth()) / 2;

            for (int i = 0; i < gPoints.size(); i++) {
                g1 = gPoints.get(i);
                g1Error = g1.getY() * g1.getProb();
                xPoints[i] = g1.getX() + w;
                yPoints[i] = g1.getY() + (int) g1Error + w;
            }
            for (int i = 0; i < gPoints.size(); i++) {

                g1 = gPoints.get(i);
                g1LowError = g1.getY() * g1.getLowerProb();
                xPoints[xPoints.length - i - 1] = g1.getX() + w;
                yPoints[yPoints.length - i - 1] = g1.getY() - (int) g1LowError + w;
            }
            g.setColor(Color.lightGray);
            g.fillPolygon(xPoints, yPoints, gPoints.size() * 2);

            for (int i = 1; i < rPoints.size(); i++) {
                g1 = rPoints.get(i - 1);
                g2 = rPoints.get(i);
                g.setColor(Color.RED);
                
            //    g.drawLine(g1.getX() + w, g1.getY() + w, g2.getX() + w, g2.getY() + w);
                
                drawLine(g1.getX() + w, g1.getY() + w, g2.getX() + w, g2.getY() + w,2,g);
            }


            for (int i = 1; i < gPoints.size(); i++) {
                g1 = gPoints.get(i - 1);
                g2 = gPoints.get(i);
                g.setColor(Color.blue);
                int x1 = g1.getX() + w;
                int y1 = g1.getY() + w;
                int x2 = g2.getX() + w;
                int y2 = g2.getY() + w;
              //  g.drawLine(x1, y1, x2, y2);
                drawLine(x1, y1, x2, y2,2,g);
                g.setColor(Color.BLUE);
                g1Error = g1.getY() * g1.getProb();
                g2Error = g2.getY() * g2.getProb();
                g1LowError = g1.getY() * g1.getLowerProb();
                g2LowError = g2.getY() * g2.getLowerProb();

                //  g.drawLine(g1.getX()+w, g1.getY()-(int)g1LowError+w, g2.getX()+w, g2.getY()-(int)g2LowError+w);
                //  g.drawLine(g1.getX()+w, g1.getY()+(int)g1Error+w, g2.getX()+w, g2.getY()+(int)g2Error+w);
                if (i == nrOfTrains) {
                    g.setColor(Color.black);
                    g.fillRect(g2.getX() + w + w, 0, 2, this.getHeight());
                }
            }

        }
        }
    }

    /**
     * This method is called from within the constructor to initialize the form.
     * WARNING: Do NOT modify this code. The content of this method is always
     * regenerated by the Form Editor.
     */
    // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
    private void initComponents() {

        setBackground(new java.awt.Color(204, 204, 204));
        setLayout(new org.netbeans.lib.awtextra.AbsoluteLayout());
    }// </editor-fold>//GEN-END:initComponents

    public void componentResized(ComponentEvent e) {
        update();
    }

    public void componentMoved(ComponentEvent e) {
        //  throw new UnsupportedOperationException("Not supported yet.");
    }

    public void componentShown(ComponentEvent e) {
        //    throw new UnsupportedOperationException("Not supported yet.");
    }

    public void componentHidden(ComponentEvent e) {
        //     throw new UnsupportedOperationException("Not supported yet.");
    }
    // Variables declaration - do not modify//GEN-BEGIN:variables
    // End of variables declaration//GEN-END:variables
}
